/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.submit;

import java.io.File;
import java.util.Date;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import net.bioteam.cloud.cluster.ActiveCluster;
import net.bioteam.cloud.cluster.ActiveHost;
import net.bioteam.cloud.cluster.ClusterStatus;
import net.bioteam.appweb.model.Program;
import net.bioteam.appweb.model.ProgramBuilder;
import net.bioteam.common.user.User;
import net.bioteam.common.utils.MyEntityManager;
import net.bioteam.appweb.ws.WsClient;

public class SoapCommandSubmitter extends BaseCommandSubmitter
{

	// the local programs configurations that should not be sent to remote host
	public static String localConfigs[] = { "_DRMAACATEGORY", "_cluster", "_MPIPREFIX" };

	// TODO support any cluster id
	public boolean canSubmit(UnfinishedJob job) throws Exception
	{
		EntityManager em = (EntityManager) MyEntityManager.getEntityManager();
		long clusterid = job.getClusterid();

		ActiveCluster ac = em.find(ActiveCluster.class, clusterid);

		if (ac == null)
		{
			// if there is no cluster fot this job, this is an error.
			// we leave the job collector to leave this job to aborted state.
			return true;
		}
		return ac.canRunJob();

	}

	public UnfinishedJob submitCommand(UnfinishedJob job) throws Exception
	{
		File workdir = new File(job.getWorkdir());
		Map<String, String> valueMap = getProperties(workdir);
		Program p = ProgramBuilder.getProgram(job.getProgramName());
		ProgramValueBean bean = new ProgramValueBean(p);
		bean.setValueMap(valueMap);

		EntityManager em = (EntityManager) MyEntityManager.getEntityManager();
		long clusterid = job.getClusterid();
		ActiveCluster ac = em.find(ActiveCluster.class, clusterid);
		if (ac == null)
		{
			logger.info("cluster for job " + job.getId() + " does not exist");
			job.setCode(RunStatusCode.ABORTED);
			job.setTrials(job.getTrials() + 1);
			job.setNote("cluster does not exist anymore");
			EntityTransaction tx = em.getTransaction();

			// only store the workdir name.
			tx.begin();
			em.flush();
			tx.commit();
			return job;
		}

		User user = em.find(User.class, Long.parseLong(job.getUsername()));
		ActiveHost head = ac.getHead();
		String serviceURL = "http://" + head.getExternalName() + ":8080/appweb/services/programws";
		WsClient client = new WsClient(user, serviceURL, null);
		try
		{
			for (String c : localConfigs)
			{
				bean.getValueMap().remove(c);
			}
			String rets[] = client.runProgram(bean);
			job.setRemoteJobId(rets[0]);
			job.setTrials(job.getTrials() + 1);
			job.setNote("submitted to remote cluster");
			job.setSubmittedTime(new Date());
			job.setCode(RunStatusCode.SUBMITTED);
			job.setCmdline(rets[2]);

			logger.info("submitted job " + job.getId());
			ac.setStatus(ClusterStatus.RUNNING);
			return job;
		} catch (Exception e)
		{
			job.setCode(RunStatusCode.FAILEDSUBMISSION);
			job.setTrials(job.getTrials() + 1);
			job.setNote(e.getMessage());
			throw e;
		} finally
		{
			EntityTransaction tx = em.getTransaction();

			// only store the workdir name.
			tx.begin();
			em.flush();
			tx.commit();

		}
	}

	public void killJob(RunStatus rs) throws Exception
	{
		EntityManager em = MyEntityManager.getEntityManager();
		User user = em.find(User.class, Long.parseLong(rs.getUsername()));

		long clusterid = rs.getClusterid();
		ActiveCluster ac = em.find(ActiveCluster.class, clusterid);
		if (ac == null)
		{
			logger.info("cluster for job " + rs.getId() + " does not exist");
			throw new Exception("can not find cluster for job. No action is taken");
		}
		logger.info("kill job "+rs.getRemoteJobId());
		if (rs.getJobid()==null)
		{
			throw new Exception("DRM ID is not available yet, try later");
		}
		ActiveHost head = ac.getHead();
		String serviceURL = "http://" + head.getExternalName() + ":8080/appweb/services/programws";
		WsClient client = new WsClient(user, serviceURL, null);
		client.killJob(rs.getRemoteJobId());

	}

}
